package edu.washington.cs.sounddetector.server.api.object;

import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

/**
 * <p>
 * SoundFormat specifies the format of a linear PCM encoded sound. This class is serves essentially
 * the same function as javax.sound.sampled.AudioFormat, but the javax.sound.sampled package is not
 * available on Android phones.
 * </p>
 * 
 * @author the.dylan.price@gmail.com
 * 
 */
public class SoundFormat
{

    private float sampleRate;
    private int sampleSizeInBits;
    private int channels;
    private boolean signed;
    private boolean bigEndian;

    public SoundFormat()
    {
    }

    /**
     * Construct a new SoundFormat.
     * 
     * @param sampleRate
     *            the number of samples per second
     * @param sampleSizeInBits
     *            the number of bits in each sample
     * @param channels
     *            the number of channels (1 for mono, 2 for stereo, and so on)
     * @param signed
     *            indicates whether the data is signed or unsigned
     * @param bigEndian
     *            indicates whether the data for a single sample is stored in big-endian byte order
     *            (false means little-endian)
     */
    public SoundFormat(float sampleRate, int sampleSizeInBits, int channels, boolean signed,
            boolean bigEndian)
    {
        Validate.isTrue(sampleRate > 0);
        Validate.isTrue(sampleSizeInBits > 0);
        Validate.isTrue(channels > 0);

        this.sampleRate = sampleRate;
        this.sampleSizeInBits = sampleSizeInBits;
        this.channels = channels;
        this.signed = signed;
        this.bigEndian = bigEndian;
    }

    /**
     * @return the sampleRate
     */
    public float getSampleRate()
    {
        return sampleRate;
    }

    /**
     * @return the sampleSizeInBits
     */
    public int getSampleSizeInBits()
    {
        return sampleSizeInBits;
    }

    /**
     * @return the channels
     */
    public int getChannels()
    {
        return channels;
    }

    /**
     * @return the signed
     */
    public boolean isSigned()
    {
        return signed;
    }

    /**
     * @return the bigEndian
     */
    public boolean isBigEndian()
    {
        return bigEndian;
    }

    @Override
    public String toString()
    {
        return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
                .append("sampleRate", sampleRate).append("sampleSizeInBits", sampleSizeInBits)
                .append("channels", channels).append("signed", signed)
                .append("bigEndian", bigEndian).toString();
    }

    @Override
    public int hashCode()
    {
        return new HashCodeBuilder().append(sampleRate).append(sampleSizeInBits).append(channels)
                .append(signed).append(bigEndian).hashCode();
    }

    @Override
    public boolean equals(Object obj)
    {
        if (!(obj instanceof SoundFormat))
        {
            return false;
        }
        SoundFormat other = (SoundFormat) obj;
        return new EqualsBuilder().append(this.sampleRate, other.sampleRate)
                .append(this.sampleSizeInBits, other.sampleSizeInBits)
                .append(this.channels, other.channels).append(this.signed, other.signed)
                .append(this.bigEndian, other.bigEndian).isEquals();
    }
}
